<!DOCTYPE html><html lang="en"><head><meta charset="UTF-8"><title>Title</title></head><body><div class="cl-preview-section"><h1 id="【图解】flutter异常与crash">【图解】Flutter异常与Crash</h1>
</div><div class="cl-preview-section"><p><img src="https://o.devio.org/images/fa/res/flutter-crash.png" alt="flutter-crash"></p>
</div><div class="cl-preview-section"><p>Flutter异常指的是Flutter程序在运行时所抛出的异常分为：</p>
</div><div class="cl-preview-section"><ul>
<li>Dart代码运行时发生的异常</li>
<li>Flutter框架异常</li>
<li>原生代码运行时抛出的异常，如：Android 的Java和kotlin，iOS的OC和swift</li>
</ul>
</div><div class="cl-preview-section"><blockquote>
<p>做Flutter应用Dart代码占绝大多数，所以本文我们重点学习下Flutter中Dart和框架异常的捕获与收集。</p>
</blockquote>
</div><div class="cl-preview-section"><p>Dart代码运行时发生的异常与Java、kotlin、OC等具有多线程模型的编程语言不同，Dart是一门单线程的编程语言，采用事件循环机制来运行任务，所以各个任务的运行状态是互相独立的。也即是说，当程序运行过程中出现异常时，即使没有像Java那样使用try-catch机制来捕获异常，Dart程序也不会退出，只会导致当前任务后续的代码不会被执行，而其它功能仍然可以继续使用。</p>
</div><div class="cl-preview-section"><h2 id="异常捕获">异常捕获</h2>
</div><div class="cl-preview-section"><p>根据异常代码的执行时序，Dart异常可以分为同步和异步异常两类。首先我们看同步异常的捕获方式：</p>
</div><div class="cl-preview-section"><blockquote>
<p>同步异常的捕获方式：</p>
</blockquote>
</div><div class="cl-preview-section"><pre class=" language-dart"><code class="prism  language-dart"><span class="token comment">//使用try-catch捕获同步异常</span>
    <span class="token keyword">try</span> <span class="token punctuation">{</span>
      <span class="token keyword">throw</span> <span class="token function">StateError</span><span class="token punctuation">(</span><span class="token string">'There is a dart exception.'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span> <span class="token keyword">catch</span> <span class="token punctuation">(</span><span class="token class-name">e</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
      <span class="token function">print</span><span class="token punctuation">(</span>e<span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>
</code></pre>
</div><div class="cl-preview-section"><blockquote>
<p>异步异常捕获方式：</p>
</blockquote>
</div><div class="cl-preview-section"><p>异步异常的捕获有两种方式：</p>
</div><div class="cl-preview-section"><ul>
<li>一种是使用Future提供的catchError语句来进行捕获；</li>
<li>另外一种是将异步转同步然后通过try-catch进行捕获；</li>
</ul>
</div><div class="cl-preview-section"><pre class=" language-dart"><code class="prism  language-dart">    <span class="token comment">//使用catchError捕获异步异常</span>
    Future<span class="token punctuation">.</span><span class="token function">delayed</span><span class="token punctuation">(</span><span class="token function">Duration</span><span class="token punctuation">(</span>seconds<span class="token punctuation">:</span> <span class="token number">1</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
        <span class="token punctuation">.</span><span class="token function">then</span><span class="token punctuation">(</span>
            <span class="token punctuation">(</span>e<span class="token punctuation">)</span> <span class="token operator">=</span><span class="token operator">&gt;</span> <span class="token keyword">throw</span> <span class="token function">StateError</span><span class="token punctuation">(</span><span class="token string">'This is first Dart exception in Future.'</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
        <span class="token punctuation">.</span><span class="token function">catchError</span><span class="token punctuation">(</span><span class="token punctuation">(</span>e<span class="token punctuation">)</span> <span class="token operator">=</span><span class="token operator">&gt;</span> <span class="token function">print</span><span class="token punctuation">(</span>e<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token keyword">try</span> <span class="token punctuation">{</span>
      <span class="token keyword">await</span> Future<span class="token punctuation">.</span><span class="token function">delayed</span><span class="token punctuation">(</span><span class="token function">Duration</span><span class="token punctuation">(</span>seconds<span class="token punctuation">:</span> <span class="token number">1</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">then</span><span class="token punctuation">(</span>
          <span class="token punctuation">(</span>e<span class="token punctuation">)</span> <span class="token operator">=</span><span class="token operator">&gt;</span> <span class="token keyword">throw</span> <span class="token function">StateError</span><span class="token punctuation">(</span><span class="token string">'This is second Dart exception in Future.'</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span> <span class="token keyword">catch</span> <span class="token punctuation">(</span><span class="token class-name">e</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
      <span class="token function">print</span><span class="token punctuation">(</span>e<span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>
</code></pre>
</div><div class="cl-preview-section"><h2 id="集中捕获异常">集中捕获异常</h2>
</div><div class="cl-preview-section"><p>在Android中我们可以通过<code>Thread.UncaughtExceptionHandler</code>接口来集中收集异常，那么在Flutter中如何集中收集异常呢？</p>
</div><div class="cl-preview-section"><p>Flutter提供的<code>Zone.runZonedGuarded()</code>方法。在Dart语言中，Zone表示一个代码执行的环境范围，其概念类似沙盒，不同沙盒之间是互相隔离的。如果想要处理沙盒中代码执行出现的异常，可以使用沙盒提供的onError回调函数来拦截那些在代码执行过程中未捕获的异常：</p>
</div><div class="cl-preview-section"><pre class=" language-dart"><code class="prism  language-dart">    <span class="token function">runZonedGuarded</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
      <span class="token keyword">throw</span> <span class="token function">StateError</span><span class="token punctuation">(</span><span class="token string">'runZonedGuarded:This is a Dart exception.'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token punctuation">(</span>e<span class="token punctuation">,</span> s<span class="token punctuation">)</span> <span class="token operator">=</span><span class="token operator">&gt;</span> <span class="token function">print</span><span class="token punctuation">(</span>e<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token function">runZonedGuarded</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
      Future<span class="token punctuation">.</span><span class="token function">delayed</span><span class="token punctuation">(</span><span class="token function">Duration</span><span class="token punctuation">(</span>seconds<span class="token punctuation">:</span> <span class="token number">1</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">then</span><span class="token punctuation">(</span><span class="token punctuation">(</span>e<span class="token punctuation">)</span> <span class="token operator">=</span><span class="token operator">&gt;</span> <span class="token keyword">throw</span> <span class="token function">StateError</span><span class="token punctuation">(</span>
          <span class="token string">'runZonedGuarded:sThis is a Dart exception in Future.'</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token punctuation">(</span>e<span class="token punctuation">,</span> s<span class="token punctuation">)</span> <span class="token operator">=</span><span class="token operator">&gt;</span> <span class="token function">print</span><span class="token punctuation">(</span>e<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre>
</div><div class="cl-preview-section"><p>从上述代码中不难看出，无论是同步异常还是异步异常，都可以使用Zone直接捕获到。同时，如果需要集中捕获Flutter应用中未处理的异常，那么可以把main函数中的runApp语句也放置在Zone中，这样就可以在检测到代码运行异常时对捕获的异常信息进行统一处理：</p>
</div><div class="cl-preview-section"><pre class=" language-dart"><code class="prism  language-dart">  runZonedGuarded<span class="token operator">&lt;</span>Future<span class="token operator">&lt;</span>Null<span class="token operator">&gt;&gt;</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token keyword">async</span> <span class="token punctuation">{</span>
    <span class="token function">runApp</span><span class="token punctuation">(</span><span class="token function">BiliApp</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token punctuation">(</span>e<span class="token punctuation">,</span> s<span class="token punctuation">)</span> <span class="token operator">=</span><span class="token operator">&gt;</span> <span class="token function">print</span><span class="token punctuation">(</span>e<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre>
</div><div class="cl-preview-section"><h2 id="案例">案例</h2>
</div><div class="cl-preview-section"><pre class=" language-dart"><code class="prism  language-dart"><span class="token keyword">void</span> <span class="token function">main</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token function">HiDefend</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">run</span><span class="token punctuation">(</span><span class="token function">BiliApp</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">.</span>
<span class="token keyword">class</span> <span class="token class-name">HiDefend</span> <span class="token punctuation">{</span>
  <span class="token function">run</span><span class="token punctuation">(</span>Widget app<span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token comment">//框架异常</span>
    FlutterError<span class="token punctuation">.</span>onError <span class="token operator">=</span> <span class="token punctuation">(</span>FlutterErrorDetails details<span class="token punctuation">)</span> <span class="token keyword">async</span> <span class="token punctuation">{</span>
      <span class="token comment">//线上环境，走上报逻辑</span>
      <span class="token keyword">if</span> <span class="token punctuation">(</span>kReleaseMode<span class="token punctuation">)</span> <span class="token punctuation">{</span>
        Zone<span class="token punctuation">.</span>current<span class="token punctuation">.</span><span class="token function">handleUncaughtError</span><span class="token punctuation">(</span>details<span class="token punctuation">.</span>exception<span class="token punctuation">,</span> details<span class="token punctuation">.</span>stack<span class="token punctuation">)</span><span class="token punctuation">;</span>
      <span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token punctuation">{</span>
        <span class="token comment">//开发期间，走Console抛出</span>
        FlutterError<span class="token punctuation">.</span><span class="token function">dumpErrorToConsole</span><span class="token punctuation">(</span>details<span class="token punctuation">)</span><span class="token punctuation">;</span>
      <span class="token punctuation">}</span>
    <span class="token punctuation">}</span><span class="token punctuation">;</span>
    runZonedGuarded<span class="token operator">&lt;</span>Future<span class="token operator">&lt;</span>Null<span class="token operator">&gt;&gt;</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token keyword">async</span> <span class="token punctuation">{</span>
      <span class="token function">runApp</span><span class="token punctuation">(</span>app<span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token punctuation">(</span>e<span class="token punctuation">,</span> s<span class="token punctuation">)</span> <span class="token operator">=</span><span class="token operator">&gt;</span> <span class="token function">_reportError</span><span class="token punctuation">(</span>e<span class="token punctuation">,</span> s<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token punctuation">}</span>

  <span class="token comment">///通过接口上报</span>
  Future<span class="token operator">&lt;</span>Null<span class="token operator">&gt;</span> <span class="token function">_reportError</span><span class="token punctuation">(</span>Object error<span class="token punctuation">,</span> StackTrace stack<span class="token punctuation">)</span> <span class="token keyword">async</span> <span class="token punctuation">{</span>
    <span class="token function">print</span><span class="token punctuation">(</span><span class="token string">'catch error：$error'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token punctuation">}</span>
<span class="token punctuation">}</span>
</code></pre>
</div><div class="cl-preview-section"><h2 id="异常上报">异常上报</h2>
</div><div class="cl-preview-section"><p>捕获到异常后可以在上述<code>_reportError</code>方法中上报到服务端，像BAT等一线互联网大厂都有自己的Crash监控平台。如果公司没有自己的Crash平台，可以接入第三方的如：Buggly。</p>
</div><div class="cl-preview-section"><ul>
<li><a href="https://pub.dev/packages?q=bugly">https://pub.dev/packages?q=bugly</a></li>
</ul>
</div> <h1 style="color: red">认准一手，获取完整资料<br>QQ3195303913<br>微信wxywd8<br><br><br><br>高价回收正版课</h1></body></html>